/**
 * Copyright (c) 2011, Ranjith TV
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright notice,
       this list of conditions and the following disclaimer
 *     in the documentation and/or other materials provided with the distribution.
 *   * Neither the name the Ranjith nor the names of its contributors may be used
       to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <string>
#include "rmk.h"
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <sstream>
#include <time.h>

using namespace std;

std::vector<struct NameValPair *> pairs;
unsigned int uid2 = 0x100039CE;
unsigned int uid3 = 0x0;

void generateSymbianFiles(std::vector<struct NameValPair *> &);
void generateINFFile(std::vector<struct NameValPair *> &);
void generateMMPFile(std::vector<struct NameValPair *> &);
void generateResourceFile(std::vector<struct NameValPair *> &);
void generateMainFile(std::vector<struct NameValPair *> &);
void generatePKGFile(std::vector<struct NameValPair *> &);

std::vector<std::string> * getFiles(int name, std::vector<struct NameValPair *> & pairs);

#ifdef __cplusplus
extern "C"
{
#endif

    extern int currentline;

    void yyerror(char const *msg)
    {
        std::cerr << msg  << " in line " << currentline << std::endl;
    }

    int yywrap()
    {
        return 1;
    }

    void addNameValPairProperty(int name, struct NameValPair *values)
    {
        values->name = name;
        pairs.push_back(values);
    }

    struct NameValPair *addNVPair(struct NameValPair *pair, int name, char *value) {
        pair->name = name;
        ((std::vector<std::string> *)pair->data)->push_back(value);
        return pair;
    }

    struct NameValPair *createNVPair(int name, char *value) {
        struct NameValPair *pair = new struct NameValPair;
        pair->name = name;
        pair->data = (char *)new std::vector<std::string>;
        ((std::vector<std::string> *)pair->data)->push_back(value);
        return pair;
    }

#ifdef __cplusplus
}
#endif

void generateUIDs();

std::string getMMPFileName(std::vector<struct NameValPair *> & pairs);
std::string getProjectName(std::vector<struct NameValPair *> & pairs);

void generateOutput()
{
    generateSymbianFiles(pairs);
}

void generateSymbianFiles(std::vector<struct NameValPair *> & pairs)
{
    generateUIDs();
    generateINFFile(pairs);
    generateMMPFile(pairs);
    generateResourceFile(pairs);
    generatePKGFile(pairs);
}

void generateINFFile(std::vector<struct NameValPair *> & pairs)
{
    std::ofstream inffile;
    inffile.open("bld.inf");

    inffile << "/********************************************" << std::endl;
    inffile << " * auto generated do not edit" << std::endl;
    inffile << " ********************************************/" << std::endl;
    inffile << std::endl;


    inffile << "#define BLD_INF_" << getProjectName(pairs) << std::endl;
    inffile << std::endl;
    inffile << "prj_platforms" << std::endl;
    inffile << "WINSCW GCCE ARMV5 ARMV6" << std::endl;
    inffile << std::endl;
    inffile << "prj_mmpfiles" << std::endl;
    inffile << getMMPFileName(pairs) << std::endl;
    inffile << std::endl;
    inffile << "#if defined(WINSCW)" << std::endl;
    inffile << "#endif" << std::endl;
    inffile << std::endl;

    inffile.close();
}

void generateMMPFile(std::vector<struct NameValPair *> & pairs)
{
    std::ofstream mmpfile;

    mmpfile.open(getMMPFileName(pairs).c_str());

    mmpfile << "/*******************************************************************" << std::endl;
    mmpfile << " * Generated by rmk" << std::endl;
    mmpfile << " *******************************************************************/" << std::endl;
    mmpfile << std::endl;

    mmpfile << "TARGET         " << getProjectName(pairs) << ".exe" << std::endl;
    mmpfile << "TARGETTYPE     " << "EXE" << std::endl;
    mmpfile << std::endl;


    mmpfile << "UID            " << std::hex << "0x" << uid2 << " " << std::hex << "0x" << uid3 << std::endl;
    mmpfile << "SECUREID       " << std::hex << "0x" << uid3 << std::endl;
    mmpfile << std::endl;

    mmpfile << "EPOCSTACKSIZE  0x14000" << std::endl;
    mmpfile << "EPOCHEAPSIZE   0x20000 0x1000000" << std::endl;
    mmpfile << std::endl;

    mmpfile << "SOURCEPATH     ." << std::endl;
    mmpfile << "LANG           SC" << std::endl;
    mmpfile << "START RESOURCE " << getProjectName(pairs) << ".rss" << std::endl;
    mmpfile << "HEADER" << std::endl;
    mmpfile << "TARGETPATH     /resource/apps" << std::endl;
    mmpfile << "END" << std::endl;
    mmpfile << std::endl;

    mmpfile << "SOURCEPATH     ." << std::endl;
    mmpfile << "START RESOURCE " << getProjectName(pairs) << "_reg.rss" << std::endl;
    mmpfile << "DEPENDS        " << getProjectName(pairs) << ".rsg" << std::endl;
    mmpfile << "TARGETPATH     /private/10003a3f/import/apps" << std::endl;
    mmpfile << "END"  << std::endl;
    mmpfile << std::endl;

    mmpfile << "SYSTEMINCLUDE  /epoc32/include/mw" << std::endl;
    mmpfile << "SYSTEMINCLUDE  /epoc32/include" << std::endl;
    mmpfile << "SYSTEMINCLUDE  /epoc32/include/stdapis" << std::endl;
    mmpfile << "SYSTEMINCLUDE  /epoc32/include/stdapis/sys" << std::endl;
    mmpfile << "SYSTEMINCLUDE  /epoc32/include/stdapis/stlportv5" << std::endl;
    mmpfile << "SYSTEMINCLUDE  /epoc32/include/platform/mw" << std::endl;
    mmpfile << "SYSTEMINCLUDE  /epoc32/include/platform" << std::endl;
    mmpfile << "SYSTEMINCLUDE  /epoc32/include/platform/loc" << std::endl;
    mmpfile << "SYSTEMINCLUDE  /epoc32/include/platform/mw/loc" << std::endl;
    mmpfile << "SYSTEMINCLUDE  /epoc32/include/platform/loc/sc" << std::endl;
    mmpfile << "SYSTEMINCLUDE  /epoc32/include/platform/mw/loc/sc" << std::endl;
    mmpfile << "SYSTEMINCLUDE  /epoc32/include/app" << std::endl;
    mmpfile << "SYSTEMINCLUDE  /epoc32/include/platform/app" << std::endl;
    mmpfile << "SYSTEMINCLUDE  /epoc32/include/platform/app/loc" << std::endl;
    mmpfile << "SYSTEMINCLUDE  /epoc32/include/platform/app/loc/sc" << std::endl;
    mmpfile << std::endl;

    mmpfile << "SOURCEPATH     ." << std::endl;
    std::vector<std::string> * files = getFiles(SOURCE, pairs);
    if (files) {
        for (std::vector<std::string>::iterator iter = files->begin();
             iter != files->end(); ++iter) {
            mmpfile << "SOURCE        " << *iter << std::endl;
        }
    }

    mmpfile << std::endl;

    mmpfile << "USERINCLUDE    ." << std::endl;
    files = getFiles(INCLUDE, pairs);
    if (files) {
        for (std::vector<std::string>::iterator iter = files->begin();
             iter != files->end(); ++iter) {
            mmpfile << "USERINCLUDE    " << *iter << std::endl;
        }
    }
    mmpfile << std::endl;

    mmpfile << "LIBRARY           libstdcppv5.lib" << std::endl;
    mmpfile << "LIBRARY           libpthread.lib" << std::endl;
    mmpfile << "LIBRARY           libc.lib" << std::endl;
    mmpfile << "LIBRARY           libm.lib" << std::endl;
    mmpfile << "LIBRARY           euser.lib" << std::endl;
    mmpfile << "LIBRARY           libdl.lib" << std::endl;
    mmpfile << "LIBRARY           cone.lib" << std::endl;
    mmpfile << "LIBRARY           eikcore.lib" << std::endl;
    mmpfile << "LIBRARY           eikcoctl.lib" << std::endl;
    mmpfile << "LIBRARY           eiksrv.lib" << std::endl;
    mmpfile << "LIBRARY           apparc.lib" << std::endl;
    mmpfile << "LIBRARY           avkon.lib" << std::endl;
    mmpfile << "LIBRARY           efsrv.lib" << std::endl;
    mmpfile << "LIBRARY           charconv.lib" << std::endl;
    mmpfile << "LIBRARY           ws32.lib" << std::endl;
    mmpfile << "LIBRARY           hal.lib" << std::endl;
    mmpfile << "LIBRARY           gdi.lib" << std::endl;
    mmpfile << "LIBRARY           libEGL.lib" << std::endl;

    files = getFiles(LIBRARY, pairs);
    if (files) {
        for (std::vector<std::string>::iterator iter = files->begin();
             iter != files->end(); ++iter) {
            mmpfile << "LIBRARY        " << *iter << std::endl;
        }
    }
    mmpfile << std::endl;
    mmpfile << "CAPABILITY       None" << std::endl;
    mmpfile << std::endl;

    mmpfile << "STDCPP" << std::endl;
    mmpfile << std::endl;

    mmpfile.close();
}

void generateResourceFile(std::vector<struct NameValPair *> & pairs)
{
    std::ofstream rssfile;
    std::string rssfilename = getProjectName(pairs) + ".rss";
    rssfile.open(rssfilename.c_str());

    rssfile << "/********************************************" << std::endl;
    rssfile << " * auto generated do not edit" << std::endl;
    rssfile << " ********************************************/" << std::endl;
    rssfile << std::endl;

    rssfile << "#include <appinfo.rh>" << std::endl;

    rssfile << "RESOURCE LOCALISABLE_APP_INFO r_localisable_app_info" << std::endl;
    rssfile << "    {" << std::endl;
    rssfile << "    short_caption = \"" << getProjectName(pairs) << "\";" << std::endl;
    rssfile << "    caption_and_icon =" << std::endl;
    rssfile << "    CAPTION_AND_ICON_INFO" << std::endl;
    rssfile << "        {" << std::endl;
    rssfile << "        caption = \"" << getProjectName(pairs) << "\";" << std::endl;
    rssfile << "        number_of_icons = 0;" << std::endl;
    rssfile << "        icon_file = \"\";" << std::endl;
    rssfile << "        };" << std::endl;
    rssfile << "    }" << std::endl;
    rssfile << std::endl;
    rssfile.close();

    std::ofstream regrssfile;
    rssfilename = getProjectName(pairs) + "_reg.rss";
    regrssfile.open(rssfilename.c_str());

    regrssfile << "/********************************************" << std::endl;
    regrssfile << " * auto generated do not edit" << std::endl;
    regrssfile << " ********************************************/" << std::endl;
    regrssfile << std::endl;

    regrssfile << "#include <" << getProjectName(pairs) << ".rsg>" << std::endl;
    regrssfile << "#include <appinfo.rh>" << std::endl;
    regrssfile << std::endl;

    regrssfile << "UID2 KUidAppRegistrationResourceFile" << std::endl;
    regrssfile << "UID3 " << std::hex << "0x" << uid3 << std::endl;
    regrssfile << std::endl;

    regrssfile << "RESOURCE APP_REGISTRATION_INFO" << std::endl;
    regrssfile << "    {" << std::endl;
    regrssfile << "    app_file=" << getProjectName(pairs) << ";" << std::endl;
    regrssfile << "    localisable_resource_file=qtn_loc_resource_file_1;" << std::endl;
    regrssfile << "    localisable_resource_id = R_LOCALISABLE_APP_INFO;" << std::endl;
    regrssfile << "    }" << std::endl;
    regrssfile << std::endl;
    regrssfile.close();
}

void generatePKGFile(std::vector<struct NameValPair *> & pair)
{
    std::string projectName = getProjectName(pairs);

    std::string pkgfilename =  projectName + ".pkg";

    std::ofstream pkgfile;
    pkgfile.open(pkgfilename.c_str());

    pkgfile << "; Language" << std::endl;
    pkgfile << "&EN" << std::endl;
    pkgfile << std::endl;


    pkgfile << "; SIS header: name, uid, version" << std::endl;
    pkgfile << "#{\"" << getProjectName(pairs) << "\"},(" << std::hex << "0x" << uid3 << "),1,0,0" << std::endl;
    pkgfile << std::endl;

    pkgfile << "; Default localized vendor name" << std::endl;
    pkgfile << "%{\"Vendor\"}" << std::endl;
    pkgfile << std::endl;

    pkgfile << "; Default unique vendor name" << std::endl;
    pkgfile << ":\"Vendor\"" << std::endl;
    pkgfile << std::endl;

    pkgfile << "; DEPLOYMENT" << std::endl;
    pkgfile << "\"/epoc32/release/armv5/urel/" << projectName << ".exe\" - \"!:\\sys\\bin\\"
            << projectName << ".exe\"" << std::endl;
    pkgfile << "\"/epoc32/data/z/resource/apps/" << projectName << ".rsc\" - \"!:\\resource\\apps\\"
            << projectName << ".rsc\"" << std::endl;

    pkgfile << "\"/epoc32/data/z/private/10003a3f/import/apps/"
            << projectName << "_reg.rsc\" - \"!:\\private\\10003a3f\\import\\apps\\"
            << projectName << "_reg.rsc\"" << std::endl;
    pkgfile << std::endl;

    pkgfile.close();
}

void generateUIDs()
{
    if (uid3 == 0) {
        uid2 = 0x100039CE;
        time_t rawtime;
        tm *ptm;

        time(&rawtime);

        ptm = gmtime(&rawtime);

        uid3 = (ptm->tm_year) << 24;
        uid3 = uid3 | (ptm->tm_yday << 16);
        uid3 = uid3 | (ptm->tm_hour << 8);
        uid3 = uid3 | (ptm->tm_sec << 0);
        uid3 = uid3 | 0xF0000000;
        uid3 = uid3 & 0xEFFFFFFF;
    }
}

std::string getMMPFileName(std::vector<struct NameValPair *> & pairs)
{
    return getProjectName(pairs) + ".mmp";
}

std::string getProjectName(std::vector<struct NameValPair *> & pairs)
{
    for (std::vector<struct NameValPair *>::iterator iter = pairs.begin(); iter != pairs.end(); ++iter) {
        if ((*iter)->name == BINPRG) {
            return (*((std::vector<std::string> *)((*iter)->data)))[0];
        }
    }

    return "";
}

std::vector<std::string> * getFiles(int name, std::vector<struct NameValPair *> & pairs)
{
    for (std::vector<struct NameValPair *>::iterator iter = pairs.begin(); iter != pairs.end(); ++iter) {
        if ((*iter)->name == name) {
            return ((std::vector<std::string> *)((*iter)->data));
        }
    }

    return 0;
}

